using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
using Matrix.Configuration.Events;
using Matrix.Configuration.Services;

namespace Matrix.Application.Services
{
    /// <summary>
    /// 事件追踪器实现
    /// 负责事件的链路追踪和调试
    /// </summary>
    public class EventTracer : IEventTracer, ITransientDependency
    {
        private readonly ILogger<EventTracer> _logger;
        private readonly IDistributedCache _distributedCache;
        private readonly IClock _clock;
        private readonly IConfigurationEventMetrics _metrics;

        private const string TracePrefix = "config_event_trace:";
        private const string TraceStepPrefix = "config_event_step:";
        private const string TraceStatsPrefix = "config_event_stats:";

        public EventTracer(
            ILogger<EventTracer> logger,
            IDistributedCache distributedCache,
            IClock clock,
            IConfigurationEventMetrics metrics)
        {
            _logger = logger;
            _distributedCache = distributedCache;
            _clock = clock;
            _metrics = metrics;
        }

        public async Task<EventTraceContext> StartTraceAsync(string eventId, string eventType, string? traceId = null)
        {
            if (string.IsNullOrEmpty(eventId))
            {
                throw new ArgumentException("事件ID不能为空", nameof(eventId));
            }

            if (string.IsNullOrEmpty(eventType))
            {
                throw new ArgumentException("事件类型不能为空", nameof(eventType));
            }

            var context = new EventTraceContext
            {
                EventId = eventId,
                EventType = eventType,
                TraceId = traceId ?? GenerateTraceId(),
                StartTime = _clock.Now
            };

            try
            {
                // 保存追踪上下文
                var cacheKey = GetTraceCacheKey(eventId);
                var contextData = System.Text.Json.JsonSerializer.Serialize(context);
                var expiration = TimeSpan.FromHours(24);
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };

                await _distributedCache.SetStringAsync(cacheKey, contextData, options);

                _logger.LogDebug("开始事件追踪: EventId: {EventId}, EventType: {EventType}, TraceId: {TraceId}",
                    eventId, eventType, context.TraceId);

                return context;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "开始事件追踪失败: EventId: {EventId}", eventId);
                return context;
            }
        }

        public async Task RecordStepAsync(EventTraceContext traceContext, string stepName, TimeSpan duration, bool success = true, string? errorMessage = null)
        {
            if (traceContext == null)
            {
                throw new ArgumentNullException(nameof(traceContext));
            }

            if (string.IsNullOrEmpty(stepName))
            {
                throw new ArgumentException("步骤名称不能为空", nameof(stepName));
            }

            try
            {
                var step = new EventTraceStep
                {
                    StepName = stepName,
                    StartTime = _clock.Now - duration,
                    Duration = duration,
                    Success = success,
                    ErrorMessage = errorMessage
                };

                // 添加到追踪上下文
                traceContext.Steps.Add(step);

                // 保存步骤信息
                var stepKey = GetStepCacheKey(traceContext.EventId, stepName);
                var stepData = System.Text.Json.JsonSerializer.Serialize(step);
                var expiration = TimeSpan.FromHours(24);
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };

                await _distributedCache.SetStringAsync(stepKey, stepData, options);

                _logger.LogDebug("记录事件步骤: EventId: {EventId}, Step: {StepName}, Duration: {Duration}ms, Success: {Success}",
                    traceContext.EventId, stepName, duration.TotalMilliseconds, success);

                // 记录指标
                if (!success)
                {
                    _metrics.RecordEventFailure(traceContext.EventType, "StepFailure", isLocal: false);
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "记录事件步骤失败: EventId: {EventId}, Step: {StepName}",
                    traceContext.EventId, stepName);
            }
        }

        public async Task CompleteTraceAsync(EventTraceContext traceContext, bool success = true, string? errorMessage = null)
        {
            if (traceContext == null)
            {
                throw new ArgumentNullException(nameof(traceContext));
            }

            try
            {
                traceContext.Properties["Success"] = success;
                if (!string.IsNullOrEmpty(errorMessage))
                {
                    traceContext.Properties["ErrorMessage"] = errorMessage;
                }

                // 计算总耗时
                var totalDuration = _clock.Now - traceContext.StartTime;
                traceContext.Properties["TotalDuration"] = totalDuration.TotalMilliseconds;

                // 更新追踪信息
                var cacheKey = GetTraceCacheKey(traceContext.EventId);
                var contextData = System.Text.Json.JsonSerializer.Serialize(traceContext);
                var expiration = TimeSpan.FromDays(7); // 追踪信息保留更长时间
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };

                await _distributedCache.SetStringAsync(cacheKey, contextData, options);

                // 更新性能统计
                await UpdatePerformanceStatsAsync(traceContext.EventType, totalDuration, success);

                _logger.LogInformation("完成事件追踪: EventId: {EventId}, EventType: {EventType}, Duration: {Duration}ms, Success: {Success}",
                    traceContext.EventId, traceContext.EventType, totalDuration.TotalMilliseconds, success);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "完成事件追踪失败: EventId: {EventId}", traceContext.EventId);
            }
        }

        public async Task<EventTraceInfo?> GetTraceInfoAsync(string eventId)
        {
            if (string.IsNullOrEmpty(eventId))
            {
                return null;
            }

            try
            {
                var cacheKey = GetTraceCacheKey(eventId);
                var contextData = await _distributedCache.GetStringAsync(cacheKey);

                if (string.IsNullOrEmpty(contextData))
                {
                    return null;
                }

                var context = System.Text.Json.JsonSerializer.Deserialize<EventTraceContext>(contextData);
                if (context == null)
                {
                    return null;
                }

                return ConvertToTraceInfo(context);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取事件追踪信息失败: EventId: {EventId}", eventId);
                return null;
            }
        }

        public async Task<List<EventTraceInfo>> GetEventsByTraceIdAsync(string traceId)
        {
            if (string.IsNullOrEmpty(traceId))
            {
                return new List<EventTraceInfo>();
            }

            try
            {
                // 这里需要扫描所有的追踪缓存，实际应用中可能需要更高效的实现
                // 可以使用Redis的SCAN命令或者维护一个TraceId到EventId的映射表

                // 简化实现：返回空列表
                _logger.LogDebug("根据TraceId获取事件列表: TraceId: {TraceId} (简化实现)", traceId);
                return new List<EventTraceInfo>();
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "根据TraceId获取事件列表失败: TraceId: {TraceId}", traceId);
                return new List<EventTraceInfo>();
            }
        }

        public async Task<EventPerformanceStats> GetPerformanceStatsAsync(string? eventType = null, TimeSpan? timeRange = null)
        {
            try
            {
                var statsKey = GetStatsCacheKey(eventType ?? "All");
                var statsData = await _distributedCache.GetStringAsync(statsKey);

                EventPerformanceStats stats;

                if (!string.IsNullOrEmpty(statsData))
                {
                    stats = System.Text.Json.JsonSerializer.Deserialize<EventPerformanceStats>(statsData)!;
                }
                else
                {
                    stats = new EventPerformanceStats
                    {
                        EventType = eventType ?? "All",
                        TotalProcessed = 0,
                        SuccessCount = 0,
                        FailureCount = 0,
                        TimeRange = (
                            _clock.Now.AddDays(-1),
                            _clock.Now)
                    };
                }

                _logger.LogDebug("获取性能统计: EventType: {EventType}, TotalProcessed: {TotalProcessed}, SuccessRate: {SuccessRate:P2}",
                    stats.EventType, stats.TotalProcessed, stats.SuccessRate);

                return stats;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取性能统计失败: EventType: {EventType}", eventType);
                return new EventPerformanceStats
                {
                    EventType = eventType ?? "All",
                    TotalProcessed = 0,
                    SuccessCount = 0,
                    FailureCount = 0,
                    TimeRange = (
                        _clock.Now.AddDays(-1),
                        _clock.Now)
                };
            }
        }

        private string GenerateTraceId()
        {
            return $"{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}[8..]";
        }

        private static string GetTraceCacheKey(string eventId)
        {
            return $"{TracePrefix}{eventId}";
        }

        private static string GetStepCacheKey(string eventId, string stepName)
        {
            return $"{TraceStepPrefix}{eventId}:{stepName}";
        }

        private static string GetStatsCacheKey(string eventType)
        {
            return $"{TraceStatsPrefix}{eventType}";
        }

        private static EventTraceInfo ConvertToTraceInfo(EventTraceContext context)
        {
            return new EventTraceInfo
            {
                EventId = context.EventId,
                EventType = context.EventType,
                TraceId = context.TraceId,
                StartTime = context.StartTime,
                EndTime = context.StartTime + GetTotalDuration(context),
                TotalDuration = GetTotalDuration(context),
                Success = context.Properties.TryGetValue("Success", out var successObj) &&
                         successObj is bool success && success,
                ErrorMessage = context.Properties.TryGetValue("ErrorMessage", out var errorObj) &&
                             errorObj is string error ? error : null,
                Steps = context.Steps.ToList(),
                Properties = new Dictionary<string, object>(context.Properties)
            };
        }

        private static TimeSpan GetTotalDuration(EventTraceContext context)
        {
            var totalMs = context.Properties.TryGetValue("TotalDuration", out var durationObj) &&
                          durationObj is double durationMs ? durationMs : 0;

            return TimeSpan.FromMilliseconds(totalMs);
        }

        private async Task UpdatePerformanceStatsAsync(string eventType, TimeSpan duration, bool success)
        {
            try
            {
                var statsKey = GetStatsCacheKey(eventType);
                var statsData = await _distributedCache.GetStringAsync(statsKey);

                EventPerformanceStats stats;

                if (!string.IsNullOrEmpty(statsData))
                {
                    stats = System.Text.Json.JsonSerializer.Deserialize<EventPerformanceStats>(statsData)!;
                }
                else
                {
                    stats = new EventPerformanceStats
                    {
                        EventType = eventType,
                        TotalProcessed = 0,
                        SuccessCount = 0,
                        FailureCount = 0,
                        AverageProcessingTimeMs = 0,
                        MinProcessingTimeMs = double.MaxValue,
                        MaxProcessingTimeMs = 0,
                        TimeRange = (
                            _clock.Now.AddDays(-1),
                            _clock.Now)
                    };
                }

                // 更新统计数据
                stats.TotalProcessed++;
                if (success)
                {
                    stats.SuccessCount++;
                }
                else
                {
                    stats.FailureCount++;
                }

                var durationMs = duration.TotalMilliseconds;
                stats.AverageProcessingTimeMs =
                    (stats.AverageProcessingTimeMs * (stats.TotalProcessed - 1) + durationMs) / stats.TotalProcessed;

                stats.MinProcessingTimeMs = Math.Min(stats.MinProcessingTimeMs, durationMs);
                stats.MaxProcessingTimeMs = Math.Max(stats.MaxProcessingTimeMs, durationMs);

                // 保存更新后的统计数据
                var updatedStatsData = System.Text.Json.JsonSerializer.Serialize(stats);
                var expiration = TimeSpan.FromHours(1);
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };
                await _distributedCache.SetStringAsync(statsKey, updatedStatsData, options);

                _logger.LogDebug("性能统计已更新: EventType: {EventType}, Duration: {Duration}ms, Success: {Success}",
                    eventType, durationMs, success);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "更新性能统计失败: EventType: {EventType}", eventType);
            }
        }
    }
}